﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Pavilion.DesignerTool
{
    public class BrushTool : IDrawTool
    {
        public string Name { get { return this.GetType().Name; } }
        public float Size { get; set; }
        public int Opacity { get { return BrushColor.A; } set { SetOpacity(value); } }
        public Color BrushColor { get; set; }

        private Texture2D brushTexture;
        private Render render;
        private Vector2 previousPoint;

        public BrushTool()
        {
            Size = 10;
            BrushColor = Color.Red;
            render = new Render();
        }

        public void Load()
        {
            RenderBrushTexture();
        }

        public void BeginExecution(DrawingBoardData data)
        {
            Vector2 adjustedPoint = data.GetAdjustedPenPosition();
            RenderPoint(adjustedPoint, data.TextureData, data.PressurePercentage);

            previousPoint = adjustedPoint;
        }

        public void Execute(DrawingBoardData data)
        {
            Vector2 adjustedPoint = data.GetAdjustedPenPosition();
            RenderLine(previousPoint, adjustedPoint, data.TextureData, data.PressurePercentage);

            previousPoint = adjustedPoint;
        }

        public void EndExecution(DrawingBoardData data, Action creatUndoPointAction)
        {
            Execute(data);
            creatUndoPointAction.Invoke();
        }

        public void DrawInterface(DrawingBoardData data)
        {
            if (data.IsMouseInsideDrawingBoard && Size > 0)
            {
                float radius = (Size * (4f / 3f)) / 2f;
                DrawManager.Instance.DrawCircle(data.PenPosition, radius, Color.Black);
            }
        }

        private void RenderPoint(Vector2 point, TextureData textureData, float pressurePercentage)
        {
            render.Begin(textureData.Texture.Width, textureData.Texture.Height);

            DrawManager.Instance.DrawOnScreen(textureData.Texture.TextureItem, new Vector2(0, 0), new Rectangle(0, 0, textureData.Texture.Width, textureData.Texture.Height), Color.White);
            this.Draw(point, pressurePercentage);

            render.End();

            textureData.UpdateTexture(render.Texture);
        }

        private void RenderLine(Vector2 startPoint, Vector2 endPoint, TextureData textureData, float pressurePercentage)
        {
            float distance, width, height, xSlope, ySlope;

            width = endPoint.X - startPoint.X;
            height = endPoint.Y - startPoint.Y;
            distance = (float)Math.Sqrt((double)((height * height) + (width * width)));
            xSlope = width / distance;
            ySlope = height / distance;

            render.Begin(textureData.Texture.Width, textureData.Texture.Height);

            DrawManager.Instance.DrawOnScreen(textureData.Texture.TextureItem, new Vector2(0, 0), new Rectangle(0, 0, textureData.Texture.Width, textureData.Texture.Height), Color.White);
            for (int i = 0; i <= distance; i++)
                this.Draw(new Vector2(startPoint.X + ((float)i * xSlope), startPoint.Y + ((float)i * ySlope)), pressurePercentage);

            render.End();

            textureData.UpdateTexture(render.Texture);
        }

        private void RenderBrushTexture()
        {
            render.Begin(20, 20);
            DrawManager.Instance.FillRectangleOnScreen(new Rectangle(0, 0, 20, 20), new Color(255, 255, 255, 255));
            render.End();

            brushTexture = render.Texture;
        }

        private void Draw(Vector2 point, float pressurePercentage)
        {
            Vector2 origin;

            if (Size > 1)
                origin = new Vector2(brushTexture.Width / 2);
            else
                origin = new Vector2(1);

            float scale = CalculateBrushScale((int)Size, brushTexture.Width, pressurePercentage);

            for (float i = 0f; i <= 20f; i += 0.05f)
                DrawManager.Instance.DrawOnScreen(brushTexture, point, new Rectangle(0, 0, brushTexture.Width, brushTexture.Height),
                    BrushColor, i, origin, scale, SpriteEffects.None, 0f);
        }

        private float CalculateBrushScale(int size, int width, float pressurePercentage) { return ((size * pressurePercentage) / (float)width); }

        private void SetOpacity(int value)
        {
            if (value < 0 || value > 255)
                throw new Exception();

            BrushColor = new Color(BrushColor.R, BrushColor.G, BrushColor.B, value);
        }
    }
}
